import random
import sys
import time
import requests, time
from datetime import datetime
import cv2 as cv
import threading
import requests
import json
import configparser
import numpy as np
import socket
import traceback
import os
from paho.mqtt import publish
from paho.mqtt import MQTTException as MQTTException
import paho.mqtt.client as mqtt
from SpinLock import SpinLock_mutex
import os
from datetime import datetime,timedelta

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

cf = configparser.ConfigParser()
cf.read(os.path.join(BASE_DIR, 'config.ini'), encoding='UTF-8')
logName = "./log/runLogging.log"
secs = cf.sections()
host = cf.get("mqtt", "host")
port = int(cf.get("mqtt", "port"))
username = cf.get("mqtt", "userName")
password = cf.get("mqtt", "userPassWorld")
send_message_topic = cf.get("mqtt", "send_message_topic")
client_id = f'ketang-{random.randint(0, 1000)}'  # 唯一设备号
auth = {
    "username": username,
    "password": password
}
protMap = {
}
m_splock = SpinLock_mutex()



def getFilePath() -> str:
    # 获取当前日期和时间
    now = datetime.now()
    formatted_date = now.strftime("%m%d")
    file_path = "log/sendMsgLog_" + formatted_date + ".log"
    return file_path
# 切换备份文件
def backup():
    filepath = getFilePath()
    if not os.path.exists(filepath):
        m_splock.acquire()
        with open(filepath, "w") as file:
            # 创建新文件并备份
            oldfilename = "log/sendMsgLog_" + ((datetime.now() - timedelta(days=1)).strftime("%m%d")) + ".log"
            if os.path.exists(oldfilename):
                newfilname = oldfilename + "." + datetime.now().strftime("%d%m%y%H%M%S")
                os.rename(oldfilename, newfilname)
        m_splock.release()

class MyThread(threading.Thread):
    def __init__(self, target, args=()):
        """
        why: 因为threading类没有返回值,因此在此处重新定义MyThread类,使线程拥有返回值
        此方法来源 https://www.cnblogs.com/hujq1029/p/7219163.html?utm_source=itdadao&utm_medium=referral
        """
        super(MyThread, self).__init__()
        self.func = target
        self.args = args
        self.result = None

    def run(self):
        # 接受返回值
        self.result = self.func(*self.args)

    def get_result(self):
        # 线程不结束,返回值为None
        try:
            return self.result
        except Exception as e:
            print(traceback.format_exc())
            return None


# 为了限制真实请求时间或函数执行时间的装饰器
def limit_decor(limit_time):
    """
    :param limit_time: 设置最大允许执行时长,单位:秒
    :return: 未超时返回被装饰函数返回值,超时则返回 None
    """

    def functions(func):
        # 执行操作
        def run(*params):
            thre_func = MyThread(target=func, args=params)
            # 主线程结束(超出时长),则线程方法结束
            thre_func.setDaemon(True)
            thre_func.start()
            # 计算分段沉睡次数
            sleep_num = int(limit_time // 1)
            sleep_nums = round(limit_time % 1, 1)
            # 多次短暂沉睡并尝试获取返回值
            for i in range(sleep_num):
                time.sleep(1)
                infor = thre_func.get_result()
                if infor:
                    return infor
            time.sleep(sleep_nums)
            # 最终返回值(不论线程是否已结束)
            if thre_func.get_result():
                return thre_func.get_result()
            else:
                return -1  # 超时返回  可以自定义

        return run

    return functions


# 接口函数
def VideoCapture(address):
    # 这里把逻辑封装成一个函数,使用线程调用
    a_theadiing = MyThread(target=a2, args=([address]))
    a_theadiing.start()
    a_theadiing.join()

    # 返回结果
    a = a_theadiing.get_result()
    return a


@limit_decor(10)  # 超时设置为3s   2s逻辑未执行完毕返回接口超时
def a2(address):
    # 创建VideoCapture对象来打开RTSP视频流
    cap = cv.VideoCapture(address)
    return cap


def isNetChainOK(testserver):
    s = socket.socket()
    s.settimeout(3)
    try:
        status = s.connect_ex(testserver)
        if status == 0:
            s.close()
            return True
        else:
            return False
    except Exception as e:
        return False


def judgeNet(testserver=('www.baidu.com', 443)):
    isOK = isNetChainOK(testserver)
    return isOK

# 用mqtt发送消息  new
class MqttRoad(object):
    def __init__(self, mqtt_host, mqtt_port, auth,send_topic=""):
        super(MqttRoad, self).__init__()
        self.client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1)
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        self.client.on_publish = self.on_publish
        self.client.on_disconnect=self.on_disconnect
        self.client.connect(mqtt_host, mqtt_port, 60)  # 60为keepalive的时间间隔
        self.client.username_pw_set(auth["username"], auth["password"])
        self.client.reconnect_delay_set(min_delay=1, max_delay=120)
        self.send_topic = send_topic
        self.client.loop_start()  # 保持连接
    def on_connect(self, client, userdata, flags, rc):
        if rc==0:
            print("Connected MQTT with result code: " + str(rc))
        else:
            client.reconnect()

    def on_message(self, client, userdata, msg):
        # print("on_message topic:" + msg.topic + " message:" + str(msg.payload.decode('utf-8')))
        pass
    #   订阅回调
    def on_subscribe(self, client, userdata, mid, granted_qos):
        print("On Subscribed: qos = %d" % granted_qos)
        pass

    #   取消订阅回调
    def on_unsubscribe(self, client, userdata, mid):
        # print("取消订阅")
        print("On unSubscribed: qos = %d" % mid)
        pass

        #   发布消息回调
    def on_publish(self, client, userdata, mid):
        # print("发布消息")
        # print("On onPublish: qos = %d" % mid)
        pass

    #   断开链接回调
    def on_disconnect(self, client, userdata, rc):
        print("断开链接")
        print("Unexpected disconnection rc = " + str(rc))
        while rc!=0:
            try:
                rc=client.reconnect()
                print("Reconnected to MQTT broker with code: " + str(rc))
            except MQTTException as e:
                print(f"Failed to reconnect to MQTT broker {e}")
    def publish(self,data,qos):
        self.client.publish(send_message_topic,data,qos=qos)

client = MqttRoad(mqtt_host=host, mqtt_port=port, auth=auth,
                  send_topic=send_message_topic)



def sendMessage(param):
    try:
        backup()
        m_splock.acquire()
        with open(f"{getFilePath()}", 'a') as file:
            current_time = datetime.now()
            # 格式化时间为 yyyy-mm-dd hh24:mi:ss
            formatted_time = current_time.strftime('%Y-%m-%d %H:%M:%S')
            # print(f"{formatted_time} {param}")
            file.write(f"{formatted_time} {param}\n")
        m_splock.release()
        # print("data", param)
        client.publish(json.dumps(param),qos=1)
    except MQTTException as e:
        print(f"消息发送失败：{e}")

def get_token():
    get_token_server = cf.get("server", "get_token_server")
    params = {
        "client_id": "behavior",
        "client_secret": "behavior"
    }
    response = requests.get(get_token_server, params=params)
    if response.status_code == 200:
        data = response.json()
        access_token = "Bearer " + data['data']['access_token']
        # print(access_token)
        return access_token
    else:
        print("获取token失败,状态码：", response.status_code)
        return None


def get_camera_list(port):
    # 发送get请求并得到结果
    get_camera_list_url = cf.get("server", "get_camera_list_url")
    access_token = get_token()
    headers = {
        "Authorization": access_token
    }
    params = {
        "key": str(port)
    }
    response = requests.get(get_camera_list_url, headers=headers, params=params)
    if response.status_code == 200:
        camera_list = response.json()['data']
        replace_front={"path":r"D:\yolov5-6.2\test_video\front_3_4.mp4"}
        replace_back = {"path": r"D:\bytetrack_ketang_tkczy\video\240521back.mp4"}
        # 重命名字段并转换数据
        for item in camera_list:
            item["camera_id"] = item.pop("id")
            item["path"] = item.pop("pushAddress")
            # 调试代码，后期删除
            # if port <=5030:
            #     item["path"]=replace_front["path"]
            # else:
            #     item["path"]=replace_back["path"]
            if item["location"] == "classroom_back":
                item["person_type"] = 2
            elif item["location"] == "classroom_front":
                item["person_type"] = 1
            item.pop("location")
        return camera_list
    else:
        print("接口{}获取摄像头列表失败，状态码：{}".format(port, response.status_code))
        return None


# 摄像头掉线，则改变算法状态
def changeStaus(uuid):
    back_sever = cf.get("server", "back_sever")
    # video_sever = cf.get("server", "video_sever")
    changeStatus_url = cf.get("server", "changeStatus_url")
    url = back_sever + changeStatus_url  # 请求接口
    data = {
        'uuid': uuid,
    }
    print("我发送的data是:" + str(data))
    headers = {'Content-Type': 'application/json'}
    # 需要轉換json
    req = requests.post(url, data=json.dumps(data), headers=headers)
    return req.content


if __name__ == '__main__':
    sendMessage("ssss")
